/**
 * 系统编译环境模型
 *
 * Created by snowingsea on 2020/11/02.
 */
const equal = require('deep-equal');
const escapeRegexp = require('escape-regexp');
const mongoose = require('mongoose');
const ProjectVersion = require('./mongo/project-version');
const projectVersions = require('./project-versions');
const files = require('./files');
const common = require('./common');
const utility = require('./utility');

/**
 * 获取概要json信息
 * @param {ProjectVersion} environment 编译环境
 * @returns {Object}
 */
function getSummaryJson(environment) {
  const environmentId = environment._id; // eslint-disable-line no-underscore-dangle
  const json = projectVersions.getJson(environment);
  return {
    environmentId,
    environmentName: json.versionName,
    description: json.description,
    includes: json.includes,
    macros: json.macros,
    arguments: json.arguments[0],
    rootDirectory: json.rootDirectory,
    builtIn: json.builtIn,
  };
}

/**
 * 获取json信息
 * @param {ProjectVersion} environment 编译环境
 * @returns {Object}
 */
function getJson(environment) {
  return getSummaryJson(environment);
}

/**
 * 获取编译环境列表请求约束
 * @param {String} q 搜索关键词
 * @return {Object}
 */
function getEnvironmentOptions({ q = null }) {
  const options = {};
  // 关键词搜索
  if (q) {
    options.$or = [{
      versionName: { $regex: `.*${escapeRegexp(q)}.*` },
    }];
  }
  return options;
}

/**
 * 获取编译环境信息
 * @param {String} environmentId 系统编译环境id
 * @return {Promise}
 */
function getEnvironment(environmentId) {
  return projectVersions.getVersion(environmentId);
}

/**
 * 获取环境集合
 * @param {Array} environmentIds 编译环境id列表
 * @param {Array} exceptEnvironmentIds 不计入的编译环境id列表
 * @param {Object} options 选项
 * @return {Promise}
 */
function getEnvironments({ environmentIds, exceptEnvironmentIds }, options = {}) {
  const condition = {
    versionIds: environmentIds,
    exceptVersionIds: exceptEnvironmentIds,
  };
  return projectVersions.getVersions(condition, options);
}

/**
 * 筛选编译环境列表
 * @param {Object} pagination 分页信息
 * @param {Object} options 用户筛选项
 * @return {Promise}
 */
async function filter(pagination = {}, options = {}) {
  const { sortBy } = pagination;
  if (!sortBy || (sortBy === 'environmentId') || (sortBy === 'createAt')) {
    pagination.sortBy = '_id';
  }
  // 将系统默认编译环境放在最前面，手动计算分页
  const builtInEnvs = await projectVersions.filter({ sortBy: pagination.sortBy }, { builtIn: true, ...options });
  const len = builtInEnvs.length;
  const nobuiltInEnvs = await projectVersions.filter(
    {
      ...pagination,
      skipIndex: Math.max(0, (pagination.page - 1) * pagination.perPage - len),
    },
    { builtIn: { $exists: false }, ...options }
  );
  let reuslt = [...builtInEnvs, ...nobuiltInEnvs];
  if (pagination.page > 1) {
    reuslt = reuslt.slice(len);
  }
  reuslt = reuslt.slice(0, pagination.perPage);
  return reuslt;
}

/**
 * 编译环境数目
 * @param {Object} options 环境筛选项
 * @return {Promise}
 */
function getCount(options = {}) {
  return projectVersions.getCount(options);
}

/**
 * 添加编译环境
 * @param {String} projectId 项目id
 * @param {Object} doc 版本信息
 * @param {Project} project 编译环境项目
 * @param {User} creator 创建者
 * @return {Promise}
 */
function addEnvironment(projectId, doc, project = undefined, creator = undefined) {
  doc.versionName = doc.environmentName;
  return projectVersions.addVersion(projectId, doc, project, creator, null, true);
}

/**
 * 删除编译环境
 * @param {String} environmentId 系统编译环境id
 * @param {ProjectVersion} environment 编译环境
 * @param {Project} project 编译环境项目
 * @param {User} creator 创建者
 * @return {Promise}
 */
function removeEnvironment(
  environmentId,
  environment = undefined,
  project = undefined,
  creator = undefined // eslint-disable-line comma-dangle
) {
  return new Promise((resolve, reject) => {
    environmentId = mongoose.Types.ObjectId(environmentId);
    ProjectVersion.find({ environmentId: { $elemMatch: { $eq: environmentId } } })
      .then((res) => {
        if (!res) {
          return Promise.resolve();
        }
        const promises = res.map(async (version) => {
          const versionId = version._id;
          const newEnvironmetIds = version.environmentId.filter((id) => id.toString() !== environmentId.toString());
          const newSystems = version.systems || {};
          if (version.systems && version.systems[environmentId.toString()]) {
            delete newSystems[environmentId.toString()];
          }
          if (version.versionType === projectVersions.versionType.unitTest) {
            await projectVersions.updateVersion(versionId, { environmentId: newEnvironmetIds, systems: newSystems }, version);
          }
          await ProjectVersion.updateOne({ _id: versionId }, { environmentChanged: true });
        });
        return Promise.all(promises);
      })
      .then(() => projectVersions.removeVersion(environmentId, environment, project, creator))
      .then(resolve)
      .catch(reject);
  });
}

/**
 * 更新编译环境信息
 * @param {String} environmentId 系统编译环境id
 * @param {String} environmentName 编译环境名称
 * @param {String} description 描述
 * @param {Array} includes 包含目录列表
 * @param {Array} macros 宏开关列表
 * @param {String} args 其他配置参数
 * @param {ProjectVersion} environment 编译环境
 * @param {Project} project 编译环境项目
 * @param {User} creator 创建者
 * @return {Promise}
 */
function updateEnvironment(
  environmentId,
  {
    environmentName = undefined,
    description = undefined,
    includes = undefined,
    macros = undefined,
    arguments: args = undefined,
  },
  environment = undefined,
  project = undefined,
  creator = undefined // eslint-disable-line comma-dangle
) {
  return new Promise((resolve, reject) => {
    environmentId = mongoose.Types.ObjectId(environmentId);
    if ((args || args === '') && !utility.isArrayType(args)) {
      args = [args];
    }
    common.complementByProjectVersionId(environmentId, environment, project, creator)
      .then((res) => {
        environment = res.version;
        const doc = {
          versionName: environmentName,
          description,
          includes,
          macros,
          arguments: args,
        };
        return projectVersions.updateVersion(environmentId, doc, environment, project, creator);
      })
      .then(() => {
        let change = false;
        if (includes && !equal(includes, environment.includes)) {
          change = true;
        }
        if (macros && !equal(macros, environment.macros)) {
          change = true;
        }
        if (args && !equal(args, environment.arguments)) {
          change = true;
        }
        if (!change) {
          return Promise.resolve();
        }
        return projectVersions.updateEnvironmentChanged(environmentId, true);
      })
      .then(resolve)
      .catch(reject);
  });
}
/**
 * 更新编译环境.smartRocket 文件信息
 * @param {String|ObjectId} environmentId  编译环境id
 */
async function updateSmartRocketFile(environmentId) {
  const smartRocketFile = await files.getFileByPath(environmentId, files.VERSIONFIELNAME);
  if (!smartRocketFile) {
    return Promise.resolve();
  }
  const environment = await ProjectVersion.findById(environmentId).lean();
  return files.updateFile(
    smartRocketFile._id,
    {
      content: JSON.stringify({
        version: environment.version,
        includes: environment.includes,
        'include files': environment['include files'],
        macros: environment.macros,
        arguments: environment.arguments,
      }),
    },
    smartRocketFile
  );
}

/**
 * Export model definition object.
 */
module.exports = {
  getSummaryJson,
  getJson,

  getEnvironmentOptions,
  getEnvironment,
  getEnvironments,
  filter,
  getCount,

  addEnvironment,
  removeEnvironment,
  updateEnvironment,
  updateSmartRocketFile,
};
